/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.ec.socialfun.servicios;

import com.ec.socialfun.entidades.Parametros;
import com.ec.socialfun.entidades.Rol;
import com.ec.socialfun.entidades.Sucursal;
import com.ec.socialfun.entidades.Usuario;
import com.ec.socialfun.entidades.UsuarioRol;
import com.ec.socialfun.entidades.UsuarioSucursal;
import com.ec.socialfun.enumeradores.EstadoEnum;
import com.ec.socialfun.enumeradores.ParametrosEnum;
import com.ec.socialfun.enumeradores.TipoUsuarioEnum;
import com.ec.socialfun.excepciones.ActivarUsuarioException;
import com.ec.socialfun.excepciones.ActualizarDatosUsuarioException;
import com.ec.socialfun.excepciones.CambioContrasenaException;
import com.ec.socialfun.excepciones.CreacionUsuarioSucursalException;
import com.ec.socialfun.excepciones.CrearArchivoException;
import com.ec.socialfun.excepciones.EncriptacionException;
import com.ec.socialfun.excepciones.EnvioMailException;
import com.ec.socialfun.excepciones.ParametroException;
import com.ec.socialfun.excepciones.RegistrarUsuarioException;
import com.ec.socialfun.servicios.externos.EnvioDeMailServicio;
import com.ec.socialfun.servicios.externos.FtpServicio;
import com.ec.socialfun.util.CambioContrasena;
import com.ec.socialfun.util.EncriptacionUtil;
import com.ec.socialfun.util.IngresoLocal;
import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.jboss.logging.Logger;

/**
 *
 * @author hp
 */
@Stateless
public class UsuarioFacade extends AbstractFacade<Usuario> {

    private static final Logger LOG = Logger.getLogger(UsuarioFacade.class.getName());
    @PersistenceContext(unitName = "SocialFunPU")
    private EntityManager em;
    @EJB
    private EnvioDeMailServicio envioDeMailServicio;
    @EJB
    private RolFacade rolFacade;
    @EJB
    private ParametrosFacade parametrosFacade;
    @EJB
    private UsuarioRolFacade usuarioRolFacade;
    @EJB
    private FtpServicio ftpServicio;
    @EJB
    private SucursalFacade sucursalFacade;
    @EJB
    private UsuarioSucursalFacade usuarioSucursalFacade;
    private final String ROL_CLIENTE = "CLI";

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    public UsuarioFacade() {
        super(Usuario.class);
    }

    /**
     * registra un nuevo usuario tipo CLIENTE con estado ING y envia mail de
     * confirmacion para que realice la activacion de la cuenta
     *
     * @param usuario
     * @throws RegistrarUsuarioException
     */
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void registrarUsuario(Usuario usuario) throws RegistrarUsuarioException {

        try {
            LOG.info("registrarUsuario");
            Date fechaActual = new Date();
            usuario.setUsFechaCreacion(fechaActual);
            usuario.setUsFechaUltimoCambio(fechaActual);
            usuario.setUsEstado(EstadoEnum.INGRESADO.getCodigo());
            usuario.setUsTipo(TipoUsuarioEnum.CLIENTE.getCodigo());
            usuario.setUsContrasena(EncriptacionUtil.encriptar(usuario.getUsContrasena()));
            this.create(usuario);
            usuario.setUsCodigoActivacion(EncriptacionUtil.encriptar(usuario.getUsCodigo()));
            usuario.setUsKey(EncriptacionUtil.crearKeyUsuario(usuario.getUsCodigo()));
            this.edit(usuario);
            envioDeMailServicio.enviarMailDeConfirmacion(usuario);
        } catch (EncriptacionException e) {
            LOG.error("Error al encriptar contenido " + e);
            throw new RegistrarUsuarioException("Error al encriptar contenido " + e);
        } catch (EnvioMailException e) {
            LOG.error("Error al enviar mail de registro " + e);
            throw new RegistrarUsuarioException("Error al enviar mail de registro " + e);
        } catch (Exception e) {
            LOG.error("Error al registrar usuario " + e);
            throw new RegistrarUsuarioException("Error al registrar usuario " + e);
        }
    }

    /**
     * verifica si el mail enviado ya se encuentra registrado en la base de
     * datos
     *
     * @param mail
     * @return
     */
    public boolean verificaMailNoRegistrado(String mail) {
        LOG.info("ingresa a verificaMailNoRegistrado ");
        Query q = em.createNamedQuery("Usuario.recuperaIngresadoOActivoPorCorreo");
        q.setParameter("mail", mail);
        return q.getResultList().isEmpty() ? true : false;
    }

    /**
     * recupera usuario por su codigo de activacion el cual es unico
     *
     * @param codigoActivacion
     * @return
     */
    public Usuario recuperaUsuarioIngresadoPorCodigoActivacion(String codigoActivacion) {

        Query q = em.createNamedQuery("Usuario.recuperaIngresadoPorCodigoActivacion");
        q.setParameter("codigoActivacion", codigoActivacion);
        q.setParameter("estado", EstadoEnum.INGRESADO.getCodigo());
        return (Usuario) (q.getResultList().isEmpty() ? null : q.getResultList().iterator().next());
    }

    /**
     * cuenta el numero de usuarios tipo CLIENTE en estado ACT
     *
     * @return
     */
    public Long contadorUsuarios() {
        LOG.info("CONTADOR");
        Query q = em.createNamedQuery("Usuario.contadorUsuarios");
        q.setParameter("estado", EstadoEnum.ACTIVO.getCodigo());
        q.setParameter("tipo", ROL_CLIENTE);
        LOG.info("CONTADOR" + (Long) q.getSingleResult());
        return (Long) q.getSingleResult();
    }

    /**
     * activa usuario tipo CLIENTE, otorga rol de acceso y crea carpeta para
     * alojamiento de imagenes
     *
     * @param usuario
     * @throws ActivarUsuarioException
     */
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void activarUsuario(Usuario usuario) throws ActivarUsuarioException {

        try {
            usuario.setUsEstado(EstadoEnum.ACTIVO.getCodigo());
            this.edit(usuario);
            Parametros parametroRol = parametrosFacade.recuperaPorNombre(ParametrosEnum.NOMBRE_ROL_USUARIO.getNombre());
            Rol rol = rolFacade.recuperaPorNombre(parametroRol.getPaValor());
            if (rol == null) {
                LOG.error("Error en la obtencion del rol para cliente, rol no encontrado:  " + ParametrosEnum.NOMBRE_ROL_USUARIO.getNombre());
                throw new ActivarUsuarioException("Error en la obtencion del rol para cliente ");
            }
            UsuarioRol usuarioRol = new UsuarioRol();
            usuarioRol.setRoCodigo(rol);
            usuarioRol.setUsRoEstado(EstadoEnum.ACTIVO.getCodigo());
            usuarioRol.setUsCodigo(usuario);
            usuarioRolFacade.create(usuarioRol);
            ftpServicio.crearFicheroImagenesUsuarioFtp(usuario);

        } catch (CrearArchivoException e) {
            LOG.error("Error al crear archivo " + e);
            throw new ActivarUsuarioException(e.getMessage());
        } catch (Exception e) {
            LOG.error("Error al activar usuario: " + e);
            throw new ActivarUsuarioException("Error al activar usuario: " + e);
        }
    }

    public Usuario recuperaUsuarioPorMail(String mail) {
        Query q = em.createNamedQuery("Usuario.findByUsCorreo");
        q.setParameter("usCorreo", mail);
        return (Usuario) q.getSingleResult();
    }

    public boolean verificarUsuario(String mail) {
        Query q = em.createNamedQuery("Usuario.findByUsCorreo");
        q.setParameter("usCorreo", mail);
        return q.getResultList().isEmpty() ? true : false;
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public Usuario actualizaDatosDeUsuario(Usuario usuario) throws ActualizarDatosUsuarioException {
        try {
            LOG.info("actualizaDatosDeUsuario ");
            this.edit(usuario);
            return this.recuperarPorCodigo(usuario.getUsCodigo());
        } catch (Exception e) {
            LOG.error("Error al actualizar datos de usuario: " + e);
            throw new ActualizarDatosUsuarioException("Error al actualizar datos de usuario: " + e);
        }
    }

    public Usuario recuperarPorCodigo(Integer codigo) {
        LOG.info("CODIGO: " + codigo);
        Query q = em.createNamedQuery("Usuario.findByUsCodigo");
        q.setParameter("usCodigo", codigo);
        return (Usuario) q.getSingleResult();
    }

    /**
     * crea y activa un usuario de tipo LOCAL
     *
     * @param ingresoLocal
     * @return
     * @throws ActivarUsuarioException
     */
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public Usuario creaYActivaUsuario(IngresoLocal ingresoLocal) throws ActivarUsuarioException {
        try {
            Usuario usuario = ingresoLocal.getUsuario();
            String nombreUsuario = ingresoLocal.getLocal().getLoNombre().substring(0, ingresoLocal.getLocal().getLoNombre().length() > 19 ? 19 : ingresoLocal.getLocal().getLoNombre().length());
            Date fechaActual = new Date();
            usuario.setUsFechaCreacion(fechaActual);
            usuario.setUsFechaUltimoCambio(fechaActual);
            usuario.setUsEstado(EstadoEnum.ACTIVO.getCodigo());
            usuario.setUsTipo(TipoUsuarioEnum.LOCAL.getCodigo());
            usuario.setUsNombre(nombreUsuario);
            usuario.setUsPrimerApellido(nombreUsuario);
            usuario.setUsContrasena(EncriptacionUtil.encriptar(usuario.getUsContrasena()));
            this.create(usuario);
            usuario.setUsCodigoActivacion(EncriptacionUtil.encriptar(usuario.getUsCodigo()));
            this.edit(usuario);

            Parametros parametroRol = parametrosFacade.recuperaPorNombre(ParametrosEnum.NOMBRE_ROL_LOCAL.getNombre());
            Rol rol = rolFacade.recuperaPorNombre(parametroRol.getPaValor());
            if (rol == null) {
                LOG.error("Error en la obtencion del rol para cliente, rol no encontrado:  " + ParametrosEnum.NOMBRE_ROL_LOCAL.getNombre());
                throw new ActivarUsuarioException("Error en la obtencion del rol para cliente ");
            }
            UsuarioRol usuarioRol = new UsuarioRol();
            usuarioRol.setRoCodigo(rol);
            usuarioRol.setUsRoEstado(EstadoEnum.ACTIVO.getCodigo());
            usuarioRol.setUsCodigo(usuario);
            usuarioRolFacade.create(usuarioRol);
            return usuario;

        } catch (EncriptacionException e) {
            LOG.error(" Error al encriptar en la creacion y activacion de usuario " + e);
            throw new ActivarUsuarioException(" Error al crear y activar usuario ");
        } catch (ActivarUsuarioException e) {
            LOG.error(" Error al crear y activar usuario " + e);
            throw e;
        } catch (ParametroException e) {
            LOG.error(" Error en la recuperacion de parametros en la creacion y activacion de usuario  " + e);
            throw new ActivarUsuarioException(" Error al crear y activar usuario ");
        }
    }

    /**
     * crea un nuevo usuario tipo SUCURSAL, le asigna roles de acceso y lo
     * vincula a una sucursal
     *
     * @param usuario
     * @param sucursal
     * @throws CreacionUsuarioSucursalException
     */
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void creacionUsuarioSucursal(Usuario usuario, Sucursal sucursal) throws CreacionUsuarioSucursalException {

        try {
            sucursal = sucursalFacade.recuperarPorCodigo(sucursal.getSuCodigo());
            Date fechaActual = new Date();
            usuario.setZoCodigo(sucursal.getZoCodigo());
            usuario.setUsEstado(EstadoEnum.ACTIVO.getCodigo());
            usuario.setUsFechaCreacion(fechaActual);
            usuario.setUsFechaUltimoCambio(fechaActual);
            usuario.setUsTipo(TipoUsuarioEnum.SUCURSAL.getCodigo());
            usuario.setUsContrasena(EncriptacionUtil.encriptar(usuario.getUsContrasena()));
            this.create(usuario);
            usuario.setUsCodigoActivacion(EncriptacionUtil.encriptar(usuario.getUsCodigo()));
            this.edit(usuario);

            UsuarioSucursal usuarioSucursal = new UsuarioSucursal();
            usuarioSucursal.setUsCodigo(usuario);
            usuarioSucursal.setSuCodigo(sucursal);
            usuarioSucursalFacade.create(usuarioSucursal);

            Parametros parametroRol = parametrosFacade.recuperaPorNombre(ParametrosEnum.NOMBRE_ROL_SUCURSAL.getNombre());
            Rol rol = rolFacade.recuperaPorNombre(parametroRol.getPaValor());
            if (rol == null) {
                LOG.error("Error en la obtencion del rol para sucursal, rol no encontrado:  " + ParametrosEnum.NOMBRE_ROL_SUCURSAL.getNombre());
                throw new CreacionUsuarioSucursalException("Error en la obtencion del rol para sucursal ");
            }
            UsuarioRol usuarioRol = new UsuarioRol();
            usuarioRol.setRoCodigo(rol);
            usuarioRol.setUsRoEstado(EstadoEnum.ACTIVO.getCodigo());
            usuarioRol.setUsCodigo(usuario);
            usuarioRolFacade.create(usuarioRol);


        } catch (EncriptacionException ex) {
            LOG.error(" Error en la encriptacion de contrasena para el usuario sucursal  " + ex);
            throw new CreacionUsuarioSucursalException(" Error en la encriptacion de contrasena para el usuario sucursal ");
        } catch (ParametroException e) {
            LOG.error(" Error en la recuperacion de parametros en la creacion y activacion de usuario  " + e);
            throw new CreacionUsuarioSucursalException(" Error al crear y activar usuario ");
        }
    }

    /**
     * metodo que recupera los usuarios creados para una sucursal
     *
     * @param sucursal
     * @return
     */
    public List<Usuario> recuperaUsuariosCreadosParaSucursal(Sucursal sucursal) {
        Query q = em.createQuery("SELECT us.usCodigo FROM UsuarioSucursal us WHERE us.suCodigo.suCodigo = :sucursal AND us.usCodigo.usTipo = :tipo ");
        q.setParameter("sucursal", sucursal.getSuCodigo());
        q.setParameter("tipo", TipoUsuarioEnum.SUCURSAL.getCodigo());
        return q.getResultList();
    }

    /**
     * actualiza usuario encriptando la contrasena
     *
     * @param usuario
     * @throws ActualizarDatosUsuarioException
     */
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void actualizarUsuarioConEncriptacionDeContraena(Usuario usuario) throws ActualizarDatosUsuarioException {
        try {
            usuario.setUsContrasena(EncriptacionUtil.encriptar(usuario.getUsContrasena()));
            usuario.setUsFechaUltimoCambio(new Date());
            this.edit(usuario);
        } catch (EncriptacionException e) {
            LOG.error("Error al actualizar los datos del usuarios " + e);
            throw new ActualizarDatosUsuarioException("Error al actualizar los datos del usuarios ");
        }
    }

    /**
     * metodo que modifica la contrasena de un usuario
     *
     * @param cambioContrasena
     * @throws CambioContrasenaException
     */
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void modificarContrasenaUsuario(CambioContrasena cambioContrasena) throws CambioContrasenaException {
        try {
            Usuario usuario = this.recuperaUsuarioPorMail(cambioContrasena.getMailUsuario());
            usuario.setUsContrasena(EncriptacionUtil.encriptar(cambioContrasena.getNuevaContrasena()));
            usuario.setUsFechaUltimoCambio(new Date());
            this.edit(usuario);
        } catch (Exception e) {
            LOG.error("Error al modificar contrasena " + e);
            throw new CambioContrasenaException("No se pudo modificar la contrasena ");
        }
    }
}
